/***

    Freja 2.1.1

    Build $Thu, 30 Aug 2007 02:58:00 UTC$

    Target: minimal

    THIS FILE IS AUTOMATICALLY GENERATED.  If creating patches, please
    diff against the source tree, not this file.

    Copyright (c) 2006-2007 Cedric Savarese <cedric@veerwest.com>, Troels Knak-Nielsen <troelskn@gmail.com>
    This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>

***/

if (typeof(dojo) != "undefined") {
        dojo.provide("Freja");
}
if (typeof(Freja) == "undefined") {
        Freja = {};
}
Freja.NAME = "Freja";
Freja.VERSION = "2.1.1";
Freja.__repr__ = function () {
        return "[" + this.NAME + " " + this.VERSION + "]";
};
Freja.toString = function () {
        return this.__repr__();
};
/**
  * Single-hierarchy inheritance (class emulation)
  * @see    http://www.itsalleasy.com/2006/02/05/prototype-chain/
  *         http://www.itsalleasy.com/2006/02/24/classjs-third-time-is-the-charm/
  *
  * Extends one prototype by another.
  * The subtype will have two specialpurpose properties:
  *     superconstructor    The parent prototype's constructor
  *     supertype        The parent prototype
  */
Freja.Class = {};
Freja.Class.extend = function(subClass, superconstructor) {
        var inlineSuper = function(){};
        inlineSuper.prototype = superconstructor.prototype;
        subClass.prototype = new inlineSuper();
        subClass.prototype.constructor = subClass;
        subClass.prototype.superconstructor = superconstructor;
        subClass.prototype.supertype = superconstructor.prototype;
};

/**
 * ====================================================================
 * About
 * ====================================================================
 * Sarissa is an ECMAScript library acting as a cross-browser wrapper for native XML APIs.
 * The library supports Gecko based browsers like Mozilla and Firefox,
 * Internet Explorer (5.5+ with MSXML3.0+), Konqueror, Safari and a little of Opera
 * @version 0.9.7.6
 * @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net
 * ====================================================================
 * Licence
 * ====================================================================
 * Sarissa is free software distributed under the GNU GPL version 2 (see <a href="gpl.txt">gpl.txt</a>) or higher, 
 * GNU LGPL version 2.1 (see <a href="lgpl.txt">lgpl.txt</a>) or higher and Apache Software License 2.0 or higher 
 * (see <a href="asl.txt">asl.txt</a>). This means you can choose one of the three and use that if you like. If 
 * you make modifications under the ASL, i would appreciate it if you submitted those.
 * In case your copy of Sarissa does not include the license texts, you may find
 * them online in various formats at <a href="http://www.gnu.org">http://www.gnu.org</a> and 
 * <a href="http://www.apache.org">http://www.apache.org</a>.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
 * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
 * WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE 
 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/**
 * <p>Sarissa is a utility class. Provides "static" methods for DOMDocument, 
 * DOM Node serialization to XML strings and other utility goodies.</p>
 * @constructor
 */
function Sarissa(){};
Sarissa.PARSED_OK = "Document contains no parsing errors";
Sarissa.PARSED_EMPTY = "Document is empty";
Sarissa.PARSED_UNKNOWN_ERROR = "Not well-formed or other error";
var _sarissa_iNsCounter = 0;
var _SARISSA_IEPREFIX4XSLPARAM = "";
var _SARISSA_HAS_DOM_IMPLEMENTATION = document.implementation && true;
var _SARISSA_HAS_DOM_CREATE_DOCUMENT = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.createDocument;
var _SARISSA_HAS_DOM_FEATURE = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.hasFeature;
var _SARISSA_IS_MOZ = _SARISSA_HAS_DOM_CREATE_DOCUMENT && _SARISSA_HAS_DOM_FEATURE;
var _SARISSA_IS_SAFARI = (navigator.userAgent && navigator.vendor && (navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1 || navigator.vendor.indexOf("Apple") != -1));
var _SARISSA_IS_IE = document.all && window.ActiveXObject && navigator.userAgent.toLowerCase().indexOf("msie") > -1  && navigator.userAgent.toLowerCase().indexOf("opera") == -1;
if(!window.Node || !Node.ELEMENT_NODE){
    Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5,  ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};
};

if(typeof XMLDocument == "undefined" && typeof Document !="undefined"){ XMLDocument = Document; } 

// IE initialization
if(_SARISSA_IS_IE){
    // for XSLT parameter names, prefix needed by IE
    _SARISSA_IEPREFIX4XSLPARAM = "xsl:";
    // used to store the most recent ProgID available out of the above
    var _SARISSA_DOM_PROGID = "";
    var _SARISSA_XMLHTTP_PROGID = "";
    var _SARISSA_DOM_XMLWRITER = "";
    /**
     * Called when the Sarissa_xx.js file is parsed, to pick most recent
     * ProgIDs for IE, then gets destroyed.
     * @private
     * @param idList an array of MSXML PROGIDs from which the most recent will be picked for a given object
     * @param enabledList an array of arrays where each array has two items; the index of the PROGID for which a certain feature is enabled
     */
    Sarissa.pickRecentProgID = function (idList){
        // found progID flag
        var bFound = false;
        for(var i=0; i < idList.length && !bFound; i++){
            try{
                var oDoc = new ActiveXObject(idList[i]);
                o2Store = idList[i];
                bFound = true;
            }catch (objException){
                // trap; try next progID
            };
        };
        if (!bFound) {
            throw "Could not retreive a valid progID of Class: " + idList[idList.length-1]+". (original exception: "+e+")";
        };
        idList = null;
        return o2Store;
    };
    // pick best available MSXML progIDs
    _SARISSA_DOM_PROGID = null;
    _SARISSA_THREADEDDOM_PROGID = null;
    _SARISSA_XSLTEMPLATE_PROGID = null;
    _SARISSA_XMLHTTP_PROGID = null;
    if(!window.XMLHttpRequest){
        /**
         * Emulate XMLHttpRequest
         * @constructor
         */
        XMLHttpRequest = function() {
            if(!_SARISSA_XMLHTTP_PROGID){
                _SARISSA_XMLHTTP_PROGID = Sarissa.pickRecentProgID(["Msxml2.XMLHTTP.6.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"]);
            };
            return new ActiveXObject(_SARISSA_XMLHTTP_PROGID);
        };
    };
    // we dont need this anymore
    //============================================
    // Factory methods (IE)
    //============================================
    // see non-IE version
    Sarissa.getDomDocument = function(sUri, sName){
        if(!_SARISSA_DOM_PROGID){
            _SARISSA_DOM_PROGID = Sarissa.pickRecentProgID(["Msxml2.DOMDocument.6.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"]);
        };
        var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
        // if a root tag name was provided, we need to load it in the DOM object
        if (sName){
            // create an artifical namespace prefix 
            // or reuse existing prefix if applicable
            var prefix = "";
            if(sUri){
                if(sName.indexOf(":") > 1){
                    prefix = sName.substring(0, sName.indexOf(":"));
                    sName = sName.substring(sName.indexOf(":")+1); 
                }else{
                    prefix = "a" + (_sarissa_iNsCounter++);
                };
            };
            // use namespaces if a namespace URI exists
            if(sUri){
                oDoc.loadXML('<' + prefix+':'+sName + " xmlns:" + prefix + "=\"" + sUri + "\"" + " />");
            } else {
                oDoc.loadXML('<' + sName + " />");
            };
        };
        return oDoc;
    };
    // see non-IE version   
    Sarissa.getParseErrorText = function (oDoc) {
        var parseErrorText = Sarissa.PARSED_OK;
        if(oDoc.parseError.errorCode != 0){
            parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason + 
                "\nLocation: " + oDoc.parseError.url + 
                "\nLine Number " + oDoc.parseError.line + ", Column " + 
                oDoc.parseError.linepos + 
                ":\n" + oDoc.parseError.srcText +
                "\n";
            for(var i = 0;  i < oDoc.parseError.linepos;i++){
                parseErrorText += "-";
            };
            parseErrorText +=  "^\n";
        }
        else if(oDoc.documentElement == null){
            parseErrorText = Sarissa.PARSED_EMPTY;
        };
        return parseErrorText;
    };
    // see non-IE version
    Sarissa.setXpathNamespaces = function(oDoc, sNsSet) {
        oDoc.setProperty("SelectionLanguage", "XPath");
        oDoc.setProperty("SelectionNamespaces", sNsSet);
    };   
    /**
     * Basic implementation of Mozilla's XSLTProcessor for IE. 
     * Reuses the same XSLT stylesheet for multiple transforms
     * @constructor
     */
    XSLTProcessor = function(){
        if(!_SARISSA_XSLTEMPLATE_PROGID){
            _SARISSA_XSLTEMPLATE_PROGID = Sarissa.pickRecentProgID(["Msxml2.XSLTemplate.6.0", "MSXML2.XSLTemplate.3.0"]);
        };
        this.template = new ActiveXObject(_SARISSA_XSLTEMPLATE_PROGID);
        this.processor = null;
    };
    /**
     * Imports the given XSLT DOM and compiles it to a reusable transform
     * <b>Note:</b> If the stylesheet was loaded from a URL and contains xsl:import or xsl:include elements,it will be reloaded to resolve those
     * @argument xslDoc The XSLT DOMDocument to import
     */
    XSLTProcessor.prototype.importStylesheet = function(xslDoc){
        if(!_SARISSA_THREADEDDOM_PROGID){
            _SARISSA_THREADEDDOM_PROGID = Sarissa.pickRecentProgID(["MSXML2.FreeThreadedDOMDocument.6.0", "MSXML2.FreeThreadedDOMDocument.3.0"]);
        };
        xslDoc.setProperty("SelectionLanguage", "XPath");
        xslDoc.setProperty("SelectionNamespaces", "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'");
        // convert stylesheet to free threaded
        var converted = new ActiveXObject(_SARISSA_THREADEDDOM_PROGID);
        // make included/imported stylesheets work if exist and xsl was originally loaded from url
        if(xslDoc.url && xslDoc.selectSingleNode("//xsl:*[local-name() = 'import' or local-name() = 'include']") != null){
            converted.async = false;
            if (_SARISSA_THREADEDDOM_PROGID == "MSXML2.FreeThreadedDOMDocument.6.0") { 
                converted.setProperty("AllowDocumentFunction", true); 
                converted.resolveExternals = true; 
            }
            converted.load(xslDoc.url);
        } else {
            converted.loadXML(xslDoc.xml);
        };
        converted.setProperty("SelectionNamespaces", "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'");
        var output = converted.selectSingleNode("//xsl:output");
        this.outputMethod = output ? output.getAttribute("method") : "html";
        this.template.stylesheet = converted;
        this.processor = this.template.createProcessor();
        // for getParameter and clearParameters
        this.paramsSet = new Array();
    };

    /**
     * Transform the given XML DOM and return the transformation result as a new DOM document
     * @argument sourceDoc The XML DOMDocument to transform
     * @return The transformation result as a DOM Document
     */
    XSLTProcessor.prototype.transformToDocument = function(sourceDoc){
        // fix for bug 1549749
        if(_SARISSA_THREADEDDOM_PROGID){
            this.processor.input=sourceDoc;
            var outDoc=new ActiveXObject(_SARISSA_DOM_PROGID);
            this.processor.output=outDoc;
            this.processor.transform();
            return outDoc;
        }
        else{
            if(!_SARISSA_DOM_XMLWRITER){
                _SARISSA_DOM_XMLWRITER = Sarissa.pickRecentProgID(["Msxml2.MXXMLWriter.6.0", "Msxml2.MXXMLWriter.3.0", "MSXML2.MXXMLWriter", "MSXML.MXXMLWriter", "Microsoft.XMLDOM"]);
            };
            this.processor.input = sourceDoc;
            var outDoc = new ActiveXObject(_SARISSA_DOM_XMLWRITER);
            this.processor.output = outDoc; 
            this.processor.transform();
            var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
            oDoc.loadXML(outDoc.output+"");
            return oDoc;
        };
    };
    
    /**
     * Transform the given XML DOM and return the transformation result as a new DOM fragment.
     * <b>Note</b>: The xsl:output method must match the nature of the owner document (XML/HTML).
     * @argument sourceDoc The XML DOMDocument to transform
     * @argument ownerDoc The owner of the result fragment
     * @return The transformation result as a DOM Document
     */
    XSLTProcessor.prototype.transformToFragment = function (sourceDoc, ownerDoc) {
        this.processor.input = sourceDoc;
        this.processor.transform();
        var s = this.processor.output;
        var f = ownerDoc.createDocumentFragment();
        if (this.outputMethod == 'text') {
            f.appendChild(ownerDoc.createTextNode(s));
        } else if (ownerDoc.body && ownerDoc.body.innerHTML) {
            var container = ownerDoc.createElement('div');
            container.innerHTML = s;
            while (container.hasChildNodes()) {
                f.appendChild(container.firstChild);
            }
        }
        else {
            var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
            if (s.substring(0, 5) == '<?xml') {
                s = s.substring(s.indexOf('?>') + 2);
            }
            var xml = ''.concat('<my>', s, '</my>');
            oDoc.loadXML(xml);
            var container = oDoc.documentElement;
            while (container.hasChildNodes()) {
                f.appendChild(container.firstChild);
            }
        }
        return f;
    };
    
    /**
     * Set global XSLT parameter of the imported stylesheet
     * @argument nsURI The parameter namespace URI
     * @argument name The parameter base name
     * @argument value The new parameter value
     */
    XSLTProcessor.prototype.setParameter = function(nsURI, name, value){
        // nsURI is optional but cannot be null 
        if(nsURI){
            this.processor.addParameter(name, value, nsURI);
        }else{
            this.processor.addParameter(name, value);
        };
        // update updated params for getParameter 
        if(!this.paramsSet[""+nsURI]){
            this.paramsSet[""+nsURI] = new Array();
        };
        this.paramsSet[""+nsURI][name] = value;
    };
    /**
     * Gets a parameter if previously set by setParameter. Returns null
     * otherwise
     * @argument name The parameter base name
     * @argument value The new parameter value
     * @return The parameter value if reviously set by setParameter, null otherwise
     */
    XSLTProcessor.prototype.getParameter = function(nsURI, name){
        nsURI = nsURI || "";
        if(this.paramsSet[nsURI] && this.paramsSet[nsURI][name]){
            return this.paramsSet[nsURI][name];
        }else{
            return null;
        };
    };
    /**
     * Clear parameters (set them to default values as defined in the stylesheet itself)
     */
    XSLTProcessor.prototype.clearParameters = function(){
        for(var nsURI in this.paramsSet){
            for(var name in this.paramsSet[nsURI]){
                if(nsURI){
                    this.processor.addParameter(name, null, nsURI);
                }else{
                    this.processor.addParameter(name, null);
                };
            };
        };
        this.paramsSet = new Array();
    };
}else{ /* end IE initialization, try to deal with real browsers now ;-) */
    if(_SARISSA_HAS_DOM_CREATE_DOCUMENT){
        /**
         * <p>Ensures the document was loaded correctly, otherwise sets the
         * parseError to -1 to indicate something went wrong. Internal use</p>
         * @private
         */
        Sarissa.__handleLoad__ = function(oDoc){
            Sarissa.__setReadyState__(oDoc, 4);
        };
        /**
        * <p>Attached by an event handler to the load event. Internal use.</p>
        * @private
        */
        _sarissa_XMLDocument_onload = function(){
            Sarissa.__handleLoad__(this);
        };
        /**
         * <p>Sets the readyState property of the given DOM Document object.
         * Internal use.</p>
         * @private
         * @argument oDoc the DOM Document object to fire the
         *          readystatechange event
         * @argument iReadyState the number to change the readystate property to
         */
        Sarissa.__setReadyState__ = function(oDoc, iReadyState){
            oDoc.readyState = iReadyState;
            oDoc.readystate = iReadyState;
            if (oDoc.onreadystatechange != null && typeof oDoc.onreadystatechange == "function")
                oDoc.onreadystatechange();
        };
        Sarissa.getDomDocument = function(sUri, sName){
            var oDoc = document.implementation.createDocument(sUri?sUri:null, sName?sName:null, null);
            if(!oDoc.onreadystatechange){
            
                /**
                * <p>Emulate IE's onreadystatechange attribute</p>
                */
                oDoc.onreadystatechange = null;
            };
            if(!oDoc.readyState){
                /**
                * <p>Emulates IE's readyState property, which always gives an integer from 0 to 4:</p>
                * <ul><li>1 == LOADING,</li>
                * <li>2 == LOADED,</li>
                * <li>3 == INTERACTIVE,</li>
                * <li>4 == COMPLETED</li></ul>
                */
                oDoc.readyState = 0;
            };
            oDoc.addEventListener("load", _sarissa_XMLDocument_onload, false);
            return oDoc;
        };
        if(window.XMLDocument){
            // do nothing
        }// TODO: check if the new document has content before trying to copynodes, check  for error handling in DOM 3 LS
        else if(_SARISSA_HAS_DOM_FEATURE && window.Document && !Document.prototype.load && document.implementation.hasFeature('LS', '3.0')){
            //Opera 9 may get the XPath branch which gives creates XMLDocument, therefore it doesn't reach here which is good
            /**
            * <p>Factory method to obtain a new DOM Document object</p>
            * @argument sUri the namespace of the root node (if any)
            * @argument sUri the local name of the root node (if any)
            * @returns a new DOM Document
            */
            Sarissa.getDomDocument = function(sUri, sName){
                var oDoc = document.implementation.createDocument(sUri?sUri:null, sName?sName:null, null);
                return oDoc;
            };
        }
        else {
            Sarissa.getDomDocument = function(sUri, sName){
                var oDoc = document.implementation.createDocument(sUri?sUri:null, sName?sName:null, null);
                // looks like safari does not create the root element for some unknown reason
                if(oDoc && (sUri || sName) && !oDoc.documentElement){
                    oDoc.appendChild(oDoc.createElementNS(sUri, sName));
                };
                return oDoc;
            };
        };
    };//if(_SARISSA_HAS_DOM_CREATE_DOCUMENT)
};
//==========================================
// Common stuff
//==========================================
if(!window.DOMParser){
    if(_SARISSA_IS_SAFARI){
        /*
         * DOMParser is a utility class, used to construct DOMDocuments from XML strings
         * @constructor
         */
        DOMParser = function() { };
        /** 
        * Construct a new DOM Document from the given XMLstring
        * @param sXml the given XML string
        * @param contentType the content type of the document the given string represents (one of text/xml, application/xml, application/xhtml+xml). 
        * @return a new DOM Document from the given XML string
        */
        DOMParser.prototype.parseFromString = function(sXml, contentType){
            var xmlhttp = new XMLHttpRequest();
            xmlhttp.open("GET", "data:text/xml;charset=utf-8," + encodeURIComponent(sXml), false);
            xmlhttp.send(null);
            return xmlhttp.responseXML;
        };
    }else if(Sarissa.getDomDocument && Sarissa.getDomDocument() && Sarissa.getDomDocument(null, "bar").xml){
        DOMParser = function() { };
        DOMParser.prototype.parseFromString = function(sXml, contentType){
            var doc = Sarissa.getDomDocument();
            doc.loadXML(sXml);
            return doc;
        };
    };
};

if((typeof(document.importNode) == "undefined") && _SARISSA_IS_IE){
    try{
        /**
        * Implementation of importNode for the context window document in IE
        * @param oNode the Node to import
        * @param bChildren whether to include the children of oNode
        * @returns the imported node for further use
        */
        document.importNode = function(oNode, bChildren){
            var tmp;
            if(oNode.nodeName == "tbody" || oNode.nodeName == "tr"){
                tmp = document.createElement("table");
            }
            else if(oNode.nodeName == "td"){
                tmp = document.createElement("tr");
            }
            else if(oNode.nodeName == "option"){
                tmp = document.createElement("select");
            }
            else{
                tmp = document.createElement("div");
            };
            if(bChildren){
                tmp.innerHTML = oNode.xml ? oNode.xml : oNode.outerHTML;
            }else{
                tmp.innerHTML = oNode.xml ? oNode.cloneNode(false).xml : oNode.cloneNode(false).outerHTML;
            };
            return tmp.getElementsByTagName("*")[0];
        };
    }catch(e){ };
};
if(!Sarissa.getParseErrorText){
    /**
     * <p>Returns a human readable description of the parsing error. Usefull
     * for debugging. Tip: append the returned error string in a &lt;pre&gt;
     * element if you want to render it.</p>
     * <p>Many thanks to Christian Stocker for the initial patch.</p>
     * @argument oDoc The target DOM document
     * @returns The parsing error description of the target Document in
     *          human readable form (preformated text)
     */
    Sarissa.getParseErrorText = function (oDoc){
        var parseErrorText = Sarissa.PARSED_OK;
        if(!oDoc.documentElement){
            parseErrorText = Sarissa.PARSED_EMPTY;
        } else if(oDoc.documentElement.tagName == "parsererror"){
            parseErrorText = oDoc.documentElement.firstChild.data;
            parseErrorText += "\n" +  oDoc.documentElement.firstChild.nextSibling.firstChild.data;
        } else if(oDoc.getElementsByTagName("parsererror").length > 0){
            var parsererror = oDoc.getElementsByTagName("parsererror")[0];
            parseErrorText = Sarissa.getText(parsererror, true)+"\n";
        } else if(oDoc.parseError && oDoc.parseError.errorCode != 0){
            parseErrorText = Sarissa.PARSED_UNKNOWN_ERROR;
        };
        return parseErrorText;
    };
};
Sarissa.getText = function(oNode, deep){
    var s = "";
    var nodes = oNode.childNodes;
    for(var i=0; i < nodes.length; i++){
        var node = nodes[i];
        var nodeType = node.nodeType;
        if(nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE){
            s += node.data;
        } else if(deep == true
                    && (nodeType == Node.ELEMENT_NODE
                        || nodeType == Node.DOCUMENT_NODE
                        || nodeType == Node.DOCUMENT_FRAGMENT_NODE)){
            s += Sarissa.getText(node, true);
        };
    };
    return s;
};
if(!window.XMLSerializer 
    && Sarissa.getDomDocument 
    && Sarissa.getDomDocument("","foo", null).xml){
    /**
     * Utility class to serialize DOM Node objects to XML strings
     * @constructor
     */
    XMLSerializer = function(){};
    /**
     * Serialize the given DOM Node to an XML string
     * @param oNode the DOM Node to serialize
     */
    XMLSerializer.prototype.serializeToString = function(oNode) {
        return oNode.xml;
    };
};

/**
 * strips tags from a markup string
 */
Sarissa.stripTags = function (s) {
    return s.replace(/<[^>]+>/g,"");
};
/**
 * <p>Deletes all child nodes of the given node</p>
 * @argument oNode the Node to empty
 */
Sarissa.clearChildNodes = function(oNode) {
    // need to check for firstChild due to opera 8 bug with hasChildNodes
    while(oNode.firstChild) {
        oNode.removeChild(oNode.firstChild);
    };
};
/**
 * <p> Copies the childNodes of nodeFrom to nodeTo</p>
 * <p> <b>Note:</b> The second object's original content is deleted before 
 * the copy operation, unless you supply a true third parameter</p>
 * @argument nodeFrom the Node to copy the childNodes from
 * @argument nodeTo the Node to copy the childNodes to
 * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is false
 */
Sarissa.copyChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {
    if((!nodeFrom) || (!nodeTo)){
        throw "Both source and destination nodes must be provided";
    };
    if(!bPreserveExisting){
        Sarissa.clearChildNodes(nodeTo);
    };
    var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
    var nodes = nodeFrom.childNodes;
    if(typeof(ownerDoc.importNode) != "undefined")  {
        for(var i=0;i < nodes.length;i++) {
            nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
        };
    } else {
        for(var i=0;i < nodes.length;i++) {
            nodeTo.appendChild(nodes[i].cloneNode(true));
        };
    };
};

/**
 * <p> Moves the childNodes of nodeFrom to nodeTo</p>
 * <p> <b>Note:</b> The second object's original content is deleted before 
 * the move operation, unless you supply a true third parameter</p>
 * @argument nodeFrom the Node to copy the childNodes from
 * @argument nodeTo the Node to copy the childNodes to
 * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is
 */ 
Sarissa.moveChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {
    if((!nodeFrom) || (!nodeTo)){
        throw "Both source and destination nodes must be provided";
    };
    if(!bPreserveExisting){
        Sarissa.clearChildNodes(nodeTo);
    };
    var nodes = nodeFrom.childNodes;
    // if within the same doc, just move, else copy and delete
    if(nodeFrom.ownerDocument == nodeTo.ownerDocument){
        while(nodeFrom.firstChild){
            nodeTo.appendChild(nodeFrom.firstChild);
        };
    } else {
        var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
        if(typeof(ownerDoc.importNode) != "undefined") {
           for(var i=0;i < nodes.length;i++) {
               nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
           };
        }else{
           for(var i=0;i < nodes.length;i++) {
               nodeTo.appendChild(nodes[i].cloneNode(true));
           };
        };
        Sarissa.clearChildNodes(nodeFrom);
    };
};

/** 
 * <p>Serialize any object to an XML string. All properties are serialized using the property name
 * as the XML element name. Array elements are rendered as <code>array-item</code> elements, 
 * using their index/key as the value of the <code>key</code> attribute.</p>
 * @argument anyObject the object to serialize
 * @argument objectName a name for that object
 * @return the XML serializationj of the given object as a string
 */
Sarissa.xmlize = function(anyObject, objectName, indentSpace){
    indentSpace = indentSpace?indentSpace:'';
    var s = indentSpace  + '<' + objectName + '>';
    var isLeaf = false;
    if(!(anyObject instanceof Object) || anyObject instanceof Number || anyObject instanceof String 
        || anyObject instanceof Boolean || anyObject instanceof Date){
        s += Sarissa.escape(""+anyObject);
        isLeaf = true;
    }else{
        s += "\n";
        var itemKey = '';
        var isArrayItem = anyObject instanceof Array;
        for(var name in anyObject){
            s += Sarissa.xmlize(anyObject[name], (isArrayItem?"array-item key=\""+name+"\"":name), indentSpace + "   ");
        };
        s += indentSpace;
    };
    return s += (objectName.indexOf(' ')!=-1?"</array-item>\n":"</" + objectName + ">\n");
};

/** 
 * Escape the given string chacters that correspond to the five predefined XML entities
 * @param sXml the string to escape
 */
Sarissa.escape = function(sXml){
    return sXml.replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&apos;");
};

/** 
 * Unescape the given string. This turns the occurences of the predefined XML 
 * entities to become the characters they represent correspond to the five predefined XML entities
 * @param sXml the string to unescape
 */
Sarissa.unescape = function(sXml){
    return sXml.replace(/&apos;/g,"'")
        .replace(/&quot;/g,"\"")
        .replace(/&gt;/g,">")
        .replace(/&lt;/g,"<")
        .replace(/&amp;/g,"&");
};
/*
 * Sarissa's IE XPath Emulation 
 */
/**
 * ====================================================================
 * About
 * ====================================================================
 * Sarissa cross browser XML library - IE XPath Emulation 
 * @version 0.9.7.6
 * @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net
 *
 * This script emulates Internet Explorer's selectNodes and selectSingleNode
 * for Mozilla. Associating namespace prefixes with URIs for your XPath queries
 * is easy with IE's setProperty. 
 * USers may also map a namespace prefix to a default (unprefixed) namespace in the
 * source document with Sarissa.setXpathNamespaces
 *
 *
 * ====================================================================
 * Licence
 * ====================================================================
 * Sarissa is free software distributed under the GNU GPL version 2 (see <a href="gpl.txt">gpl.txt</a>) or higher, 
 * GNU LGPL version 2.1 (see <a href="lgpl.txt">lgpl.txt</a>) or higher and Apache Software License 2.0 or higher 
 * (see <a href="asl.txt">asl.txt</a>). This means you can choose one of the three and use that if you like. If 
 * you make modifications under the ASL, i would appreciate it if you submitted those.
 * In case your copy of Sarissa does not include the license texts, you may find
 * them online in various formats at <a href="http://www.gnu.org">http://www.gnu.org</a> and 
 * <a href="http://www.apache.org">http://www.apache.org</a>.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
 * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
 * WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE 
 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
if(_SARISSA_HAS_DOM_FEATURE && document.implementation.hasFeature("XPath", "3.0")){
    /**
    * <p>SarissaNodeList behaves as a NodeList but is only used as a result to <code>selectNodes</code>,
    * so it also has some properties IEs proprietery object features.</p>
    * @private
    * @constructor
    * @argument i the (initial) list size
    */
    function SarissaNodeList(i){
        this.length = i;
    };
    /** <p>Set an Array as the prototype object</p> */
    SarissaNodeList.prototype = new Array(0);
    /** <p>Inherit the Array constructor </p> */
    SarissaNodeList.prototype.constructor = Array;
    /**
    * <p>Returns the node at the specified index or null if the given index
    * is greater than the list size or less than zero </p>
    * <p><b>Note</b> that in ECMAScript you can also use the square-bracket
    * array notation instead of calling <code>item</code>
    * @argument i the index of the member to return
    * @returns the member corresponding to the given index
    */
    SarissaNodeList.prototype.item = function(i) {
        return (i < 0 || i >= this.length)?null:this[i];
    };
    /**
    * <p>Emulate IE's expr property
    * (Here the SarissaNodeList object is given as the result of selectNodes).</p>
    * @returns the XPath expression passed to selectNodes that resulted in
    *          this SarissaNodeList
    */
    SarissaNodeList.prototype.expr = "";
    /** dummy, used to accept IE's stuff without throwing errors */
    if(window.XMLDocument && (!XMLDocument.prototype.setProperty)){
        XMLDocument.prototype.setProperty  = function(x,y){};
    };
    /**
    * <p>Programmatically control namespace URI/prefix mappings for XPath
    * queries.</p>
    * <p>This method comes especially handy when used to apply XPath queries
    * on XML documents with a default namespace, as there is no other way
    * of mapping that to a prefix.</p>
    * <p>Using no namespace prefix in DOM Level 3 XPath queries, implies you
    * are looking for elements in the null namespace. If you need to look
    * for nodes in the default namespace, you need to map a prefix to it
    * first like:</p>
    * <pre>Sarissa.setXpathNamespaces(oDoc, &quot;xmlns:myprefix=&amp;aposhttp://mynsURI&amp;apos&quot;);</pre>
    * <p><b>Note 1 </b>: Use this method only if the source document features
    * a default namespace (without a prefix), otherwise just use IE's setProperty
    * (moz will rezolve non-default namespaces by itself). You will need to map that
    * namespace to a prefix for queries to work.</p>
    * <p><b>Note 2 </b>: This method calls IE's setProperty method to set the
    * appropriate namespace-prefix mappings, so you dont have to do that.</p>
    * @param oDoc The target XMLDocument to set the namespace mappings for.
    * @param sNsSet A whilespace-seperated list of namespace declarations as
    *            those would appear in an XML document. E.g.:
    *            <code>&quot;xmlns:xhtml=&apos;http://www.w3.org/1999/xhtml&apos;
    * xmlns:&apos;http://www.w3.org/1999/XSL/Transform&apos;&quot;</code>
    * @throws An error if the format of the given namespace declarations is bad.
    */
    Sarissa.setXpathNamespaces = function(oDoc, sNsSet) {
        //oDoc._sarissa_setXpathNamespaces(sNsSet);
        oDoc._sarissa_useCustomResolver = true;
        var namespaces = sNsSet.indexOf(" ")>-1?sNsSet.split(" "):new Array(sNsSet);
        oDoc._sarissa_xpathNamespaces = new Array(namespaces.length);
        for(var i=0;i < namespaces.length;i++){
            var ns = namespaces[i];
            var colonPos = ns.indexOf(":");
            var assignPos = ns.indexOf("=");
            if(colonPos > 0 && assignPos > colonPos+1){
                var prefix = ns.substring(colonPos+1, assignPos);
                var uri = ns.substring(assignPos+2, ns.length-1);
                oDoc._sarissa_xpathNamespaces[prefix] = uri;
            }else{
                throw "Bad format on namespace declaration(s) given";
            };
        };
    };
    /**
    * @private Flag to control whether a custom namespace resolver should
    *          be used, set to true by Sarissa.setXpathNamespaces
    */
    XMLDocument.prototype._sarissa_useCustomResolver = false;
    /** @private */
    XMLDocument.prototype._sarissa_xpathNamespaces = new Array();
    /**
    * <p>Extends the XMLDocument to emulate IE's selectNodes.</p>
    * @argument sExpr the XPath expression to use
    * @argument contextNode this is for internal use only by the same
    *           method when called on Elements
    * @returns the result of the XPath search as a SarissaNodeList
    * @throws An error if no namespace URI is found for the given prefix.
    */
    XMLDocument.prototype.selectNodes = function(sExpr, contextNode, returnSingle){
        var nsDoc = this;
        var nsresolver = this._sarissa_useCustomResolver
        ? function(prefix){
            var s = nsDoc._sarissa_xpathNamespaces[prefix];
            if(s)return s;
            else throw "No namespace URI found for prefix: '" + prefix+"'";
            }
        : this.createNSResolver(this.documentElement);
        var result = null;
        if(!returnSingle){
            var oResult = this.evaluate(sExpr,
                (contextNode?contextNode:this),
                nsresolver,
                XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            var nodeList = new SarissaNodeList(oResult.snapshotLength);
            nodeList.expr = sExpr;
            for(var i=0;i<nodeList.length;i++)
                nodeList[i] = oResult.snapshotItem(i);
            result = nodeList;
        }
        else {
            result = oResult = this.evaluate(sExpr,
                (contextNode?contextNode:this),
                nsresolver,
                XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
        };
        return result;      
    };
    /**
    * <p>Extends the Element to emulate IE's selectNodes</p>
    * @argument sExpr the XPath expression to use
    * @returns the result of the XPath search as an (Sarissa)NodeList
    * @throws An
    *             error if invoked on an HTML Element as this is only be
    *             available to XML Elements.
    */
    Element.prototype.selectNodes = function(sExpr){
        var doc = this.ownerDocument;
        if(doc.selectNodes)
            return doc.selectNodes(sExpr, this);
        else
            throw "Method selectNodes is only supported by XML Elements";
    };
    /**
    * <p>Extends the XMLDocument to emulate IE's selectSingleNode.</p>
    * @argument sExpr the XPath expression to use
    * @argument contextNode this is for internal use only by the same
    *           method when called on Elements
    * @returns the result of the XPath search as an (Sarissa)NodeList
    */
    XMLDocument.prototype.selectSingleNode = function(sExpr, contextNode){
        var ctx = contextNode?contextNode:null;
        return this.selectNodes(sExpr, ctx, true);
    };
    /**
    * <p>Extends the Element to emulate IE's selectSingleNode.</p>
    * @argument sExpr the XPath expression to use
    * @returns the result of the XPath search as an (Sarissa)NodeList
    * @throws An error if invoked on an HTML Element as this is only be
    *             available to XML Elements.
    */
    Element.prototype.selectSingleNode = function(sExpr){
        var doc = this.ownerDocument;
        if(doc.selectSingleNode)
            return doc.selectSingleNode(sExpr, this);
        else
            throw "Method selectNodes is only supported by XML Elements";
    };
    Sarissa.IS_ENABLED_SELECT_NODES = true;
};
if(_SARISSA_IS_IE)
         Sarissa.IS_ENABLED_SELECT_NODES = true;


/**
  * Freja._aux
  * wrapper for external dependencies (frameworks).
  *
  * This is the minimal auxiliary adapter. It contains self-sufficient
  * implementations of all dependencies.
  * 
  */
if (typeof(Freja) == "undefined") {
        Freja = {};
}
Freja._aux = {};
/** bind(func, self) : function */
// from http://blog.ianbicking.org/prototype-and-object-prototype.html
Freja._aux.bind = function(func, self) {
        if(typeof (func)=="string"){
                func=self[func];
        }

        var im_func = null;
    if (typeof(func.im_func) == 'function') {
        im_func = func.im_func;
    } else {
        im_func = func;
    }
    func = function () {
        return func.im_func.apply(func.im_self, arguments);
    }
    func.im_func = im_func;
    func.im_self = self;
        return func;
};
/** formContents(elem) : Array */
Freja._aux.formContents = function(elem) {
        if (!elem) elem = document;
        var names = [];
        var values = [];
        var inputs = elem.getElementsByTagName("INPUT");
        for (var i = 0; i < inputs.length; ++i) {
                var input = inputs[i];
                if (input.name) {
                        if (input.type == "radio" || input.type == "checkbox") {
                                if (input.checked) {
                                        names.push(input.name);
                                        values.push(input.value);
                                } else {
                                        names.push(input.name);
                                        values.push("");
                                }
                        } else {
                                names.push(input.name);
                                values.push(input.value);
                        }
                }
        }
        var textareas = elem.getElementsByTagName("TEXTAREA");
        for (var i = 0; i < textareas.length; ++i) {
                var input = textareas[i];
                if (input.name) {
                        names.push(input.name);
                        values.push(input.value);
                }
        }
        var selects = elem.getElementsByTagName("SELECT");
        for (var i = 0; i < selects.length; ++i) {
                var input = selects[i];
                if (input.name) {
                        if (input.selectedIndex >= 0) {
                                var opt = input.options[input.selectedIndex];
                                names.push(input.name);
                                values.push((opt.value) ? opt.value : "");
                        }
                }
        }
        return [names, values];
};
/** getElement(id) : HTMLElement */
Freja._aux.getElement = function(id) {
        if (typeof(id) == "object") {
                return id;
        } else {
                return document.getElementById(id);
        }
};

/** connect(src, signal, fnc) : void */
Freja._aux.connect = function(src, signal, fnc) {

        if(!src) return;
        if (src.addEventListener) {
                var wrapper = function(e) {
                        var evt = {
                                stop : function() {
                                        if (e.cancelable) {
                                                e.preventDefault();
                                        }
                                        e.stopPropagation();
                                }
                        }
                        fnc(evt);
                }
                src.addEventListener(signal.replace(/^(on)/, ""), wrapper, false);
        } else if (src.attachEvent) {
                var wrapper = function() {
                        var e = window.event;
                        var evt = {
                                stop : function() {
                                        e.cancelBubble = true;
                                        e.returnValue = false;
                                }
                        }
                        fnc(evt);
                }
                src.attachEvent(signal, wrapper);
        }
        if (!src._signals) {
                src._signals = [];
        }
        if (!src._signals[signal]) {
                src._signals[signal] = [];
        }
        /*
         * @TODO Check this
         * see: http://www.formassembly.com/forums/viewtopic.php?t=282&sid=189221aa89bf7245deb04bbfb8d3c7e9
         * 
         * // checks if the callback has already been registered with the same function
         * for(var item=0; item < src._signals[signal].length;item++) {
         *      if(src._signals[signal][item].toString() == fnc.toString()) return;
         * } 
         */
         
    
        src._signals[signal].push(fnc);
};
/** signal(src, signal, ...) : void */
Freja._aux.signal = function(src, signal) {

        try {
                if(src._signals && src._signals[signal]) {
                        var sigs = src._signals[signal];
                        var args = [];
                        for (var i=2; i < arguments.length; i++) {
                                args.push(arguments[i]);
                        }
                        for (var i=0; i < sigs.length; i++) {
                                try {
                                        sigs[i].apply(src, args);
                                } catch (e) { /* squelch */ }
                        }
                }
        } catch (e) { /* squelch */ }
};
/** createDeferred() : Deferred */
Freja._aux.createDeferred = function() {
        return new Freja._aux.Deferred();
};
/** openXMLHttpRequest(method, url, async, user, pass) : XMLHttpRequest */
Freja._aux.openXMLHttpRequest = function(method, url, async, user, pass) {
        var req = new XMLHttpRequest();
        if (user && pass) {
                req.open(method, url, async, user, pass);
        } else {
                req.open(method, url, async);
        }
        if (method == "POST" || method == "PUT") {
                req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        }
        // RoR/cakePHP Ajax request detection compatibility:
        req.setRequestHeader('X-Requested-With', 'XMLHttpRequest');     
        return req;
};
/** sendXMLHttpRequest(req, sendContent) : Deferred */
Freja._aux.sendXMLHttpRequest = function(req, sendContent) {
        var d = Freja._aux.createDeferred();
        var bComplete = false;
        req.onreadystatechange = function() {
                if (req.readyState == 4 && !bComplete) {
                        if (req.status == 0 || req.status == 200 || req.status == 201 || req.status == 304) {
                                d.callback(req);
                        } else {
                                d.errback(req);
                        }
                        bComplete = true;
                }
        }
        if (!sendContent) sendContent = "";
        req.send(sendContent);
        return d;
};
/** xmlize(anyObject, objectName) : string */
Freja._aux.xmlize = Sarissa.xmlize;

/** serializeXML(node) : string */
Freja._aux.serializeXML = function(node) {
        if (node.xml) return node.xml;
        return (new XMLSerializer()).serializeToString(node);
};
/** loadXML(string) : XMLDocument */
Freja._aux.loadXML = function(text) {
        return (new DOMParser()).parseFromString(text, "text/xml");
};
/** transformXSL(XMLDocument, XSLDocument) : string */
Freja._aux.transformXSL = function(xml, xsl, xslParameters) {
        var processor = new XSLTProcessor();
        processor.importStylesheet(xsl);
        if(xslParameters) {
                for (var paramName in xslParameters) {
                        processor.setParameter("", paramName, xslParameters[paramName]);
                }
        }
         
        return processor.transformToFragment(xml, window.document);
};
/** cloneXMLDocument(document) : XMLDocument */
Freja._aux.cloneXMLDocument = function(xmlDoc) {
        var clone = null;
        try {
                clone = xmlDoc.cloneNode(true);
        } catch(e) { /* squelch */ }

        // Can't clone a DocumentNode in Safari & Opera. Let's try something else.
        // @note Wouldn't it be easier to serialize the document to string and the parse it to a new document ?
        if (!clone) {
                if (document.implementation && document.implementation.createDocument) {
                        clone = document.implementation.createDocument("", xmlDoc.documentElement.nodeName, null);
                        // importNode is not safe in Safari ! the source document is altered. used cloneNode to fix the prblm
                        var data = clone.importNode(xmlDoc.documentElement.cloneNode(true), true);
                        try {
                                clone.appendChild(data);
                        } catch(e) {
                                // Opera has already created a documentElement and can't append another root node
                                var rootNode = clone.documentElement;
                                for (var i = data.childNodes.length; i >= 0; i--) {
                                        rootNode.insertBefore(data.childNodes[i], rootNode.firstChild);
                                }
                                // need to copy root node attributes
                                for (var i = 0; i < xmlDoc.documentElement.attributes.length; i++) {
                                        var name  = xmlDoc.documentElement.attributes.item(i).name;
                                        var value = xmlDoc.documentElement.attributes.item(i).value;
                                        clone.documentElement.setAttribute(name, value);
                                }
                        }
                }
        }
        return clone;
};
/** hasSupportForXSLT() : boolean */
Freja._aux.hasSupportForXSLT = function() { return (typeof(XSLTProcessor) != "undefined"); };
/** createQueryEngine() : Freja.QueryEngine */
Freja._aux.createQueryEngine = function() {
        if (Sarissa.IS_ENABLED_SELECT_NODES) {
                return new Freja.QueryEngine.XPath();
        } else {
                return new Freja.QueryEngine.SimplePath();
        }
};
/** A pale replacement for MochiKit.Async.Deferred */
Freja._aux.Deferred = function() {
        this._good = [];
        this._bad = [];
        this._pending = null;
};
Freja._aux.Deferred.prototype.callback = function() {
        if (this._good.length == 0) {
                this._pending = [this.callback, arguments];
                return;
        }
        for (var i=0; i < this._good.length; i++) {
                this._good[i].apply(window, arguments);
        }
        this._good = [];
};
Freja._aux.Deferred.prototype.errback = function() {
        if (this._bad.length == 0) {
                this._pending = [this.errback, arguments];
                return;
        }
        for (var i=0; i < this._bad.length; i++) {
                this._bad[i].apply(window, arguments);
        }
        this._bad = [];
};
Freja._aux.Deferred.prototype.addCallbacks = function(fncOK, fncError) {
        if (fncOK) this._good[this._good.length] = fncOK;
        if (fncError) this._bad[this._bad.length] = fncError;
        if (this._pending) {
                this._pending[0].apply(this, this._pending[1]);
        }
};
Freja._aux.Deferred.prototype.addCallback = function(fncOK) {
        this.addCallbacks(fncOK);
};
Freja._aux.Deferred.prototype.addErrback = function(fncError) {
        this.addCallbacks(null, fncError);
};
Freja._aux.importNode = function(document, node, deep) {
        if(typeof deep =='undefined') deep = true;
        if(document.importNode)
                return document.importNode(node,deep);
        else
                return node.cloneNode(deep);
}
/**
  * The baseclass for queryengines
  * @abstract
  */
Freja.QueryEngine = function() {};
Freja.QueryEngine.prototype.getElementById = function(document, id) {
        // getElementById doesn't work on XML document without xml:id
        var allElements = document.getElementsByTagName("*");
        for (var i= 0; i < allElements.length; i++) {
                if (allElements[i].getAttribute("id") == id) {
                        return allElements[i];
                }
        }
};
Freja.QueryEngine.prototype.get = function(document, expression) {
        
        var node = this._find(document, expression);

        if(!node) throw new Error("Can't evaluate expression " + expression);

        switch(node.nodeType) {
                case 1: /* element */
                        // return content of text nodes
                        // @TO-DO: return more than just firstchild?
                        if(node.firstChild && (node.firstChild.nodeType == 3 || node.firstChild.nodeType == 4)) {
                                return node.firstChild.nodeValue;
                        }
                        break;
                case 2: /* Attribute */
                        return node.nodeValue;
                        break;
                case 3: /* text node */
                        // fall through
                case 4: /* CDATA section */
                        return node.nodeValue;
                        break;  
        }
        return null;
};
Freja.QueryEngine.prototype.set = function(document, expression, value) {
        var node = this._find(document, expression);
        if(!node) {
                // Could not evaluate expression.
                // Check if we're trying to set a non-existent attribute
                var nodeName = expression.substr(expression.lastIndexOf('/')+1);
                if(nodeName.charAt(0)=='@') {
                        // Let's try to create the attribute.
                        var parentExpression =  expression.substring(0, expression.lastIndexOf('/'));
                        var pNode = this._find(document, parentExpression);
                        if(pNode) {                             
                                pNode.setAttribute(nodeName.substr(1),value);
                                return;
                        }
                        // else parent node non existent either, give up.
                }
                // not an attribute, give up.
                throw new Error("Can't evaluate expression " + expression);
        }

        // Expression succesfully evaluated. Set content
        switch(node.nodeType) {
                case 1: /* element */
                        // @TO-DO: set more than just firstchild                        
                        if(node.firstChild && (node.firstChild.nodeType == 3 || node.firstChild.nodeType == 4)) {
                                node.firstChild.nodeValue = value;
                        } else {
                                if(value!="") // prevent a subsequent IE7/MSXML3 crash in view rendering.
                                        node.appendChild(document.createTextNode(value));
                        }
                        break;
                case 2: /* Attribute */
                        node.nodeValue = value;
                        break;
                case 3: /* text node */
                        // fall through
                case 4: /* CDATA section */
                        node.nodeValue = value;
                        break;  
        }
        return ;
};
/**
  * XPath query engine.
  */
Freja.QueryEngine.XPath = function() {};
Freja.Class.extend(Freja.QueryEngine.XPath, Freja.QueryEngine);
Freja.QueryEngine.XPath.prototype._find = function(document, expression) {      
        var result = document.selectSingleNode(expression);     
        return result;
};
/**
  * SimplePath
  */
Freja.QueryEngine.SimplePath = function() {};
Freja.Class.extend(Freja.QueryEngine.SimplePath, Freja.QueryEngine);
Freja.QueryEngine.SimplePath.prototype._find = function(document, expression) {
        
        if (!expression.match(/^[\d\w\/@\[\]=_\-']*$/)) {
                throw new Error("Can't evaluate expression " + expression);
        }
        var parts = expression.split("/");
        var node = document;
        var regAttr = new RegExp("^@([\\d\\w]*)");
        var regOffset = new RegExp("^([@\\d\\w]*)\\[([\\d]*)\\]$");
        var regFilter = new RegExp("^([\\d\\w]+)\\[@([@\\d\\w]+)=['\"]{1}(.*)['\"]{1}\\]$");
        var attr = null;
        var offset = 0;
        for (var i = 0; i < parts.length; ++i) {
                var part = parts[i];
                var filter = regFilter.exec(part);
                if(filter) {
                        // filter[1] element name, filter[2] attribute name, filter[3] attribute value
                        if(i>0 && parts[i-1]=='') {
                                // expression was of type //element[...]
                                var cn = node.getElementsByTagName(filter[1]);
                        } else {
                                var cn = node.childNodes;
                        }
                        for(var j=0, l=cn.length; j<l ; j++) {
                                if(cn[j].nodeType==1 && cn[j].tagName==filter[1] && cn[j].getAttribute(filter[2])== filter[3]) {
                                        node = cn[j];
                                        break;
                                }
                        }
                        if (j==l)
                                throw new Error("Can't evaluate expression " + part);
                }
                else {
                        offset = regOffset.exec(part);
                        if (offset) {
                                part = offset[1];
                                offset = offset[2] - 1;
                        } else {
                                offset = 0;
                        }
                        if (part != "") {
                                attr = regAttr.exec(part);
                                if (attr) {
                                        node = node.getAttributeNode(attr[1]);
                                } else {
                                        node = node.getElementsByTagName(part).item(offset);
                                }
                        }
                }
        }
        if (node && node.firstChild && node.firstChild.nodeType == 3) {
                return node.firstChild;
        }
        if (node && node.firstChild && node.firstChild.nodeType == 4) {
                return node.firstChild;
        }

        if (!node) {
                throw new Error("Can't evaluate expression " + expression);
        }
        return node;
};
/**
  * Standard model component
  */
Freja.Model = function(url, query) {
        this.url = url;
        this.ready = false;
        this.document = null;
        this._query = query;
};
/**
  * Returns a single value
  */
Freja.Model.prototype.getElementById = function(id) {
        if (this.document) {
                return this._query.getElementById(this.document, id);
        }
        return null;
};
/**
  * Returns a single value
  */
Freja.Model.prototype.get = function(expression) {
        if (this.document) {
                return this._query.get(this.document, expression);
        }
        return null;
};
/**
  * Updates a value
  */
Freja.Model.prototype.set = function(expression, value) {
        if (this.document) {
                return this._query.set(this.document, expression, value);
        }
        return null;
};
/**
  * Updates the model from a view
  */
Freja.Model.prototype.updateFrom = function(view) {
        var values = view.getValues();
        for (var i = 0; i < values[0].length; ++i) {
                // try not to process field names that are not meant to be xpath expressions
                if(values[0][i].lastIndexOf('/') != -1) {               
                        try {
                                this.set(values[0][i], values[1][i]);
                        } catch(x) {
                                // couldn't set the value.
                                // @TODO: Throw new Error.
                        }
                }
        }
};

/**
  * Writes the model back to the remote service
  * @returns Freja._aux.Deferred
  */
Freja.Model.prototype.save = function() {
        var url = this.url;
        var match = /^(file:\/\/.*\/)([^\/]*)$/.exec(window.location.href);
        if (match) {
                url = match[1] + url; // local
        }
        // since the serialization may fail, we create a deferred for the
        // purpose, rather than just returning the sendXMLHttpRequest directly.
        var d = Freja._aux.createDeferred();
        var req = Freja.AssetManager.openXMLHttpRequest("POST", url);
        try {
                // for some obscure reason exceptions aren't thrown back if I call the
                // shorthand version of sendXMLHttpRequest in IE6.
                Freja._aux.sendXMLHttpRequest(req, Freja._aux.serializeXML(this.document)).addCallbacks(Freja._aux.bind(d.callback, d), Freja._aux.bind(d.errback, d));
        } catch (ex) {
                d.errback(ex);
        }
        return d;
};
/**
  * Deletes the model from the remote service
  * @returns Freja._aux.Deferred
  */
Freja.Model.prototype.remove = function() {
        var url = this.url;
        var match = /^(file:\/\/.*\/)([^\/]*)$/.exec(window.location.href);
        if (match) {
                url = match[1] + url; // local
        }
        var req = Freja.AssetManager.openXMLHttpRequest("DELETE", url);
        return Freja._aux.sendXMLHttpRequest(req);
};
/**
  * @returns Freja._aux.Deferred
  */
Freja.Model.prototype.reload = function(url) {
        
        if(url) {
                // Replace old url in cache with new url
                for (var i=0; i < Freja.AssetManager.models.length; i++) {
                        if (Freja.AssetManager.models[i].url == this.url) {
                                Freja.AssetManager.models[i].url = url;
                        }
                }
                this.url = url;
        }
        
        this.ready = false;
        var onload = Freja._aux.bind(function(document) {
                this.document = document;
                this.ready = true;
                Freja._aux.signal(this, "onload");
        }, this);
        var d = Freja.AssetManager.loadAsset(this.url, true);
        d.addCallbacks(onload, Freja.AssetManager.onerror);
        return d;
};
/**
  * DataSource provides a gateway-type interface to a REST service.
  */
Freja.Model.DataSource = function(createURL, indexURL) {
        this.createURL = createURL;
        this.indexURL = indexURL;
};
/**
  * Returns a list of primary-keys to records in the datasource
  */
Freja.Model.DataSource.prototype.select = function() {
        return getModel(this.indexURL);
};
/**
  * Creates a new instance of a record
  * @todo errback to the deferred on errors
  */
Freja.Model.DataSource.prototype.create = function(values) {
        var url = this.createURL;
        var match = /^(file:\/\/.*\/)([^\/]*)$/.exec(window.location.href);
        if (match) {
                url = match[1] + url; // local
        }
        var req = Freja.AssetManager.openXMLHttpRequest("PUT", url);
        var payload = {};
        for (var i = 0, len = values[0].length; i < len; ++i) {
                payload[values[0][i]] = values[1][i];
        }
        return Freja._aux.sendXMLHttpRequest(req, Freja._aux.xmlize(payload, 'record'));
};

/**
  * Standard view component
  */
Freja.View = function(url, renderer) {
        this.url = url;
        this.ready = false;
        this.document = null;
        this._renderer = renderer;
        this._destination = null;
        this.behaviors = [];
        this.placeholder = null;
        Freja._aux.connect(this, "onrendercomplete", Freja._aux.bind(this._connectBehavior, this));
};
/**
  * @param    model            Freja.Model
  * @param    placeholder      string    If supplied, this will be used instead of the
  *                                      default placeholder.
  * @returns Freja._aux.Deferred
  */
Freja.View.prototype.render = function(model, placeholder, xslParameters) {
        if (typeof(placeholder) == "undefined") placeholder = this.placeholder;
        if (typeof(xslParameters) == "undefined") xslParameters = this.xslParameters;

        var Handler = function(model, view, deferred, xslParameters) {
                this.model = model;
                this.view = view;
                this.deferred = deferred;
                this.xslParameters = xslParameters;
        };
        Handler.prototype.trigger = function() {
                try {
                        if (!this.view.ready) {
                                Freja._aux.connect(this.view, "onload", Freja._aux.bind(this.trigger, this));
                                return;
                        }
                        if (typeof(this.model) == "object" && this.model instanceof Freja.Model && !this.model.ready) {
                                Freja._aux.connect(this.model, "onload", Freja._aux.bind(this.trigger, this));
                                return;
                        }
                        var model;
                        if (typeof(this.model) == "undefined") {
                                // supply dummy
                                model = { document : Freja._aux.loadXML("<?xml version='1.0' ?><dummy/>")};
                        } else if (this.model instanceof Freja.Model) {
                                model = this.model;
                        } else {
                                // wrap pojo's in
                                model = { document : Freja._aux.loadXML("<?xml version='1.0' ?>\n" + Freja._aux.xmlize(this.model, "item")) };
                        }

                        var trans = this.view._renderer.transform(model, this.view, this.xslParameters);
                        trans.addCallback(Freja._aux.bind(function(html) {
                                if(typeof html == "string") {
                                        this._destination.innerHTML = html;  // Remote XSLT (serialized HTML *not* XML)
                                } else {
                                        this._destination.innerHTML = "";   
                                        this._destination.appendChild(html); // Browser XSLT (DOM fragment)
                                }
                        }, this.view));
                        trans.addCallback(Freja._aux.bind(function() {
                                Freja._aux.signal(this, "onrendercomplete", this._destination)
                        }, this.view));
                        trans.addCallback(Freja._aux.bind(
                                function() { 
                                        this.deferred.callback();
                                }, this));
                        trans.addErrback(Freja._aux.bind(
                                function(ex) { 
                                        this.deferred.errback(ex);
                                }, this));
                } catch (ex) {
                        this.deferred.errback(ex);
                }
        };

        var d = Freja._aux.createDeferred();
        try {
                if (typeof(placeholder) == "object") {
                        this._destination = placeholder;
                } else {
                        this._destination = document.getElementById(placeholder);
                }
                // @todo    Is this a good idea ?
                // Perhaps we should leave it to the programmer to do this.
                this._destination.innerHTML = Freja.AssetManager.THROBBER_HTML;

                var h = new Handler(model, this, d, xslParameters);
                h.trigger();
        } catch (ex) {
                d.errback(ex);
        }
        return d;
};
/**
  * Decorates the output of the primary renderer, to inject behavior.
  * @note Maybe we could use cssQuery (http://dean.edwards.name/my/cssQuery/)
  *       to identify targets for behavior
  */
Freja.View.prototype._connectBehavior = function(destination) {
        try {
                var connectCallback = function(node, eventType, callback) {

                        Freja._aux.connect(node, eventType, Freja._aux.bind(
                                function(e) {
                                        var allow = false;
                                        try {
                                                allow = callback(this);
                                        } catch (ex) {
                                                throw new Error("An error ocurred in user handler.\n" + ex.message);
                                        } finally {
                                                if (!allow) {
                                                        e.stop();
                                                }
                                        }
                                }, node)
                        );
                };
                var applyHandlers = function(node, behaviors) {
                        for (var i = 0, c = node.childNodes, l = c.length; i < l; ++i) {
                                var child = c[i];
                                if (child.nodeType == 1) {
                                        if(child.className) {
                                                var classNames = child.className.split(' ');
                                                for (var j=0;j<classNames.length;j++) {
                                                        var handler = behaviors[classNames[j]];
                                                        if (handler) {
                                                                for (var eventType in handler) {
                                                                        if (eventType == "init") {
                                                                                handler.init(child);
                                                                        } else {
                                                                                connectCallback(child, eventType, handler[eventType]);
                                                                        }
                                                                }
                                                        }
                                                }
                                        }
                                        applyHandlers(child, behaviors);
                                }
                        }
                };

                // Avoid traversing the DOM tree if there's no handler to process.
                // @note: is there a better way? this.behaviors.length is always 0.
                // @note  This is fine. behaviors is a hashmap, not an array.
                for (var ids in this.behaviors) {
                        applyHandlers(destination, this.behaviors);
                        break;
                }

        } catch (ex) {
                alert(ex.message);
        }
};
/**
  * Returns the values of a formview
  */
Freja.View.prototype.getValues = function() {
        return Freja._aux.formContents(this._destination);
};
/**
  * Base object for viewrenderers
  */
Freja.View.Renderer = function() {};
/**
  * XSLT based render-engine
  */
Freja.View.Renderer.XSLTransformer = function() {};
Freja.Class.extend(Freja.View.Renderer.XSLTransformer, Freja.View.Renderer);
/**
  * @returns Freja._aux.Deferred
  */
Freja.View.Renderer.XSLTransformer.prototype.transform = function(model, view, xslParameters) {
        var d = Freja._aux.createDeferred();
       
        try {
                        var html = Freja._aux.transformXSL(model.document, view.document, xslParameters);
                if (!html) {
                        d.errback(new Error("XSL Transformation error."));
                } else {
                        d.callback(html);
                }
        } catch (ex) {
                d.errback(ex);
        }
        return d;
};
/**
  * XSLT on a remote service for browser which have no native support.
  * @param    url    URL of the transform service
  */
Freja.View.Renderer.RemoteXSLTransformer = function(url) {
        this.url = url;
};
Freja.Class.extend(Freja.View.Renderer.RemoteXSLTransformer, Freja.View.Renderer);
/**
  * @returns Freja._aux.Deferred
  */
Freja.View.Renderer.RemoteXSLTransformer.prototype.transform = function(model, view, xslParameters) {
        var d = Freja._aux.createDeferred();

        // prepare posted data  (no need to send the XSL document, just its url)
        var xslUrl = view.url;
        var postedData = "xslFile=" + encodeURIComponent(xslUrl) + "&xmlData=" + encodeURIComponent(Freja._aux.serializeXML(model.document));

        var xslParameterString = '';
        for (var paramname in xslParameters) {
                xslParameterString += encodeURIComponent(paramname + "," + xslParameters[paramname]);
        }
        if(xslParameterString.length > 0) {
                postedData  = postedData + '&xslParam=' + xslParameterString;
        }

        // send request to the server-side XSL transformation service
        var req = Freja.AssetManager.openXMLHttpRequest("POST", Freja.AssetManager.XSLT_SERVICE_URL);
        req.onreadystatechange = function() {
                if (req.readyState == 4) {
                        if (req.status == 200) {
                                d.callback(req.responseText);
                        } else {
                                d.errback(req.responseText);
                        }
                }
        }
        req.send(postedData);
        return d;
};
/**
  * This is largely s copied with minor stylistic adjustments from Freja 1.1
  * I renamed it from Controller.history to distinguish between window.history
  */
Freja.UndoHistory = function() {
        this.cache = [];
        this.maxLength = 5;
        this._position = 0;
        this._undoSteps = 0;
};
/**
  * Creates a snapshot of the model and stores it.
  */
Freja.UndoHistory.prototype.add = function(model) {
        var historyIndex = this._position % this.maxLength;

        var modelDoc = model.document;
        this.cache[historyIndex] = {};
        this.cache[historyIndex].model = model;
        this.cache[historyIndex].document = Freja._aux.cloneXMLDocument(modelDoc);

        if (!this.cache[historyIndex].document) {
                throw new Error("Couldn't add to history.");
        } else {
                this._position++;
                // clear rest of the history if undo was used.
                var clearHistoryIndex = historyIndex;
                while (this._undoSteps > 0) {
                        clearHistoryIndex = (clearHistoryIndex + 1) % this.maxLength;
                        this.cache[clearHistoryIndex] = {};
                        this._undoSteps--;
                }
                return historyIndex; // what would anybody need this for ?
        }
};
/**
  * Rolls the state back one step.
  */
Freja.UndoHistory.prototype.undo = function(steps) {
        if (this._undoSteps < this.cache.length) {
                this._undoSteps++;
                this._position--;
                if (this._position < 0) {
                        this._position = this.maxLength - 1;
                }

                var model = this.cache[this._position].model;
                if (this.cache[this._position].document) {
                        model.document = this.cache[this._position].document;
                } else {
                        throw new Error("The model's DOMDocument wasn't properly copied into the history");
                }
                if (typeof(steps) != "undefined" && steps > 1) {
                        this.undo(steps - 1);
                }
        } else {
                throw new Error("Nothing to undo");
        }
};
/**
  * Reverts the effects of undo.
  */
Freja.UndoHistory.prototype.redo = function() {
        if (this._undoSteps > 0) {
                this._undoSteps--;
                this._position = (this._position + 1) % this.maxLength;

                var model = this.cache[this._position].model;
                model.document = this.cache[this._position].document;
        } else {
                throw new Error("Nothing to redo");
        }
};
/**
  * Removes the last entry in the cache
  */
Freja.UndoHistory.prototype.removeLast = function() {
        this._position--;

        if (this._position < 0) {
                this._position = this.maxLength - 1;
        }
        this.cache[this._position] = {};
        this._undoSteps = 0;
};

/**
  * main repository
  * @static
  */
Freja.AssetManager = {
        models : [],
        views : [],
        _username : null,
        _password : null
};
/**
  * Set to sync to make all requests synchroneous. You shouldn't use
  * this setting for anything but testing/debugging.
  * "async" | "sync"
  */
Freja.AssetManager.HTTP_REQUEST_TYPE = "async";
/**
  * If this is set to null, real PUT and DELETE http-requests will be made,
  * otherwise a header will be set instead, and the request tunneled through
  * POST.
  *
  * Both IE6 and FF1.5 are known to support the required HTTP methods, so
  * if theese are your target platform, you can disable tunneling.
  */
//  Freja.AssetManager.HTTP_METHOD_TUNNEL = null;
  Freja.AssetManager.HTTP_METHOD_TUNNEL = "Http-Method-Equivalent";
/**
  * Set this url to provide remote xslt-transformation for browsers that
  * doesn't support it natively.
  */
Freja.AssetManager.XSLT_SERVICE_URL = "srvc-xslt.php";
/**
  * HTML displayed while waiting for stuff to happen
  */
Freja.AssetManager.THROBBER_HTML = "<span style='color:white;background:firebrick'>Loading ...</span>";
/**
  * returns an instance of the renderengine to use
  */
Freja.AssetManager.createRenderer = function() {
//      return new Freja.View.Renderer.RemoteXSLTransformer(this.XSLT_SERVICE_URL);
        if (Freja._aux.hasSupportForXSLT()) {
                return new Freja.View.Renderer.XSLTransformer();
        } else {
                return new Freja.View.Renderer.RemoteXSLTransformer(this.XSLT_SERVICE_URL);
        }
};
/**
  * Wipes all caches. This isn't something you will normally use during production,
  * but it's very helpful for debugging/testing
  */
Freja.AssetManager.clearCache = function() {
        this.models = [];
        this.views = [];
};
/**
  * Load a model-component
  * @param    url      string
  */
Freja.AssetManager.getModel = function(url) {
        for (var i=0; i < this.models.length; i++) {
                if (this.models[i].url == url) {
                        return this.models[i];
                }
        }
        var m = new Freja.Model(url, Freja._aux.createQueryEngine());
        var onload = Freja._aux.bind(function(document) {
                this.document = document;
                this.ready = true;
                Freja._aux.signal(this, "onload");
        }, m);
        this.loadAsset(url, true).addCallbacks(onload, Freja.AssetManager.onerror);
        this.models.push(m);
        return m;
};
/**
  * Load a view-component
  * @param    url      string
  */
Freja.AssetManager.getView = function(url) {
        for (var i=0; i < this.views.length; i++) {
                if (this.views[i].url == url) {
                        return this.views[i];
                }
        }
        var v = new Freja.View(url, this.createRenderer());
        var onload = Freja._aux.bind(function(document) {
                this.document = document;
                this.ready = true;
                Freja._aux.signal(this, "onload");
        }, v);
        this.loadAsset(url, false).addCallbacks(onload, Freja.AssetManager.onerror);
        this.views.push(v);
        return v;
};
/**
  * Creates and opens a http-request, tunneling exotic methods if needed.
  */
Freja.AssetManager.openXMLHttpRequest = function(method, url) {
        var tunnel = null;
        if (Freja.AssetManager.HTTP_METHOD_TUNNEL && method != "GET" && method != "POST") {
                tunnel = method;
                method = "POST";
        }
        var req = Freja._aux.openXMLHttpRequest(method, url, Freja.AssetManager.HTTP_REQUEST_TYPE == "async", Freja.AssetManager._username, Freja.AssetManager._password);
        if (tunnel) {
                req.setRequestHeader(Freja.AssetManager.HTTP_METHOD_TUNNEL, tunnel);
        }
        return req;
};
/**
  * Sets username + password for Http-Authentication
  */
Freja.AssetManager.setCredentials = function(username, password) {
        this._username = username;
        this._password = password;
};
/**
  * @returns Freja._aux.Deferred
  */
Freja.AssetManager.loadAsset = function(url, preventCaching) {
        var match = /^(file:\/\/.*\/)([^\/]*)$/.exec(window.location.href);
        if (match) {
                url = match[1] + url; // local
        }
        var d = Freja._aux.createDeferred();
        var handler = function(transport) {
                try {
                        if (transport.responseText == "") {
                                throw new Error("Empty response.");
                        }
                        if (transport.responseXML.xml == "") {
                                // The server doesn't reply with Content-Type: text/xml
                                // this will happen if the file is loaded locally (through file://)
                                var document = Freja._aux.loadXML(transport.responseText);
                        } else {
                                var document = transport.responseXML;
                        }
                } catch (ex) {
                        d.errback(ex);
                }
                if(window.document.all) {                               
                        // Weird bug in IE6 when assets are loaded from local file system.
                        // Despite the async request, the document is loaded and the onload signal is sent 
                        // before the getModel function exits (giving no chance to attach a handler to onload).
                        // Using a 1ms timeout here fixes the problem.
                        setTimeout(function() { d.callback(document); }, 1);            
                } else
                        d.callback(document);
        };
        try {
                // Why using HTTP_METHOD_TUNNEL for a GET?
                //-- to prevent caching, since browsers won't cache a POST
                if (preventCaching && Freja.AssetManager.HTTP_METHOD_TUNNEL) {
                        var req = Freja._aux.openXMLHttpRequest("POST", url, Freja.AssetManager.HTTP_REQUEST_TYPE == "async", Freja.AssetManager._username, Freja.AssetManager._password);
                        req.setRequestHeader(Freja.AssetManager.HTTP_METHOD_TUNNEL, "GET");
                        req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                } else {
                        var req = Freja._aux.openXMLHttpRequest("GET", url, Freja.AssetManager.HTTP_REQUEST_TYPE == "async", Freja.AssetManager._username, Freja.AssetManager._password);
                }

                // This shouldn't be nescesary, but alas it is - firefox chokes
                // It's probably due to an error in MochiKit, so the problem
                // should be fixed there.
                var comm = Freja._aux.sendXMLHttpRequest(req);
                if (Freja.AssetManager.HTTP_REQUEST_TYPE == "async") {
                        // fixes bug #7189 (http://developer.berlios.de/bugs/?func=detailbug&group_id=6277&bug_id=7189)
                        comm.addCallbacks(handler, function(req) {
                                d.errback(new Error("Request failed:" + req.status));
                        });
                } else {
                        if (req.status == 0 || req.status == 200 ||  req.status == 201 ||  req.status == 304) {
                                handler(req);
                        } else {
                                d.errback(new Error("Request failed:" + req.status));
                        }
                }
        } catch (ex) {
                d.errback(ex);
        }
        return d;
};
/**
  * This is a default error-handler. You should provide your own.
  * The handler is called if an asynchronous error happens, since
  * this could not be caught with the usual try ... catch
  *
  * It ought to be replaced completely with Deferred
  */
Freja.AssetManager.onerror = function(ex) {
        alert("Freja.AssetManager.onerror\n" + ex.message);
};
/**
  * Global exports
  */
window.getModel = Freja._aux.bind("getModel", Freja.AssetManager);
window.getView = Freja._aux.bind("getView", Freja.AssetManager);